﻿using Furion.ClayObject.Extensions;
using Furion.CMS.Core;
using Furion.CMS.Core.Base;
using Furion.DatabaseAccessor;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Furion.CMS.Application
{
    /// <summary>
    /// 应用服务基类
    /// </summary>
    [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
    public abstract class BaseApplication : IDynamicApiController
    {
    }

    /// <summary>
    /// 只读应用服基类
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <typeparam name="TKey"></typeparam>
    /// <typeparam name="TListDto"></typeparam>
    /// <typeparam name="TDetailDto"></typeparam>
    /// <typeparam name="TFilterParams"></typeparam>
    /// <typeparam name="TSortParams"></typeparam>
    public abstract class ReadOnlyAppService<TEntity, TKey, TListDto, TDetailDto, TFilterParams, TSortParams> : BaseApplication, IReadOnlyAppService<TEntity, TListDto, TDetailDto, TFilterParams, TSortParams>
        where TEntity : PrivateEntityBase<TKey>, new()
        where TListDto : class, new()
        where TDetailDto : class, new()
        where TFilterParams : Core.Base.BaseFilterParams<TEntity>, new()
        where TSortParams : Core.Base.BaseSortParams, new()
    {
        /// <summary>
        /// 默认应用服务仓储
        /// </summary>
        protected readonly IRepository<TEntity> _appRepository;

        /// <summary>
        /// 只读应用服基类
        /// </summary>
        /// <param name="appRepository"></param>
        protected ReadOnlyAppService(IRepository<TEntity> appRepository)
        {
            _appRepository = appRepository;
        }

        /// <summary>
        /// 分页查询
        /// </summary>
        /// <param name="index">当前页码</param>
        /// <param name="limit">每页数量</param>
        /// <param name="filter">筛选条件</param>
        /// <param name="sort">排序</param>
        /// <returns></returns>
        [HttpPost]
        public virtual PagingList<TListDto> GetPagedList([ApiSeat(ApiSeats.ActionStart)] int index, [ApiSeat(ApiSeats.ActionStart)] int limit,
            [FromQuery] TFilterParams filter,
            [FromBody] TSortParams sort = default)
        {
            // 条件过滤
            var query = FilterBeforeQueryHandle(_appRepository.AsQueryable(false))
                .Where(filter.GetFilterExpression());

            // 排序之后再进行分页处理
            var pageResult = new PagingList<TListDto> { Current = index, PageSize = limit, Total = query.Count() };

            // 排序与分页处理
            query = query.AsSortQuery(sort)
                .AsPagedQuery(index, limit);

            pageResult.List = PagedlistFilterEndQueryHandle(query);

            return pageResult;
        }

        /// <summary>
        /// 过滤查询前处理
        /// </summary>
        /// <param name="entities"></param>
        /// <returns></returns>
        protected virtual IQueryable<TEntity> FilterBeforeQueryHandle(IQueryable<TEntity> entities)
        {
            return entities;
        }

        /// <summary>
        /// 分页查询筛选后处理
        /// </summary>
        /// <param name="entities"></param>
        /// <returns></returns>
        protected virtual List<TListDto> PagedlistFilterEndQueryHandle(IQueryable<TEntity> entities)
        {
            return entities.Adapt<List<TListDto>>();
        }

        /// <summary>
        /// 查询明细数据
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [SecurityDefine]
        public virtual TDetailDto GetDetail(TKey id)
        {
            var query = _appRepository.AsQueryable(false)
                 .Where(t => t.Id.Equals(id));

            if (!query.Any()) throw Oops.Oh($"未能找到ID为 {id} 的详情数据");

            var entity = DetailFilterEndQueryHandle(query).FirstOrDefault();

            return AfterGetDetail(entity);
        }

        /// <summary>
        /// 获取明细后处理
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        protected virtual TDetailDto AfterGetDetail(TEntity entity)
        {
            return entity.Adapt<TDetailDto>();
        }

        /// <summary>
        /// 明细查询筛选后处理
        /// </summary>
        /// <param name="entities"></param>
        /// <returns></returns>
        protected virtual IQueryable<TEntity> DetailFilterEndQueryHandle(IQueryable<TEntity> entities)
        {
            return entities;
        }
    }


    /// <summary>
    /// Curd应用服务基类
    /// <para>
    /// 实现了基本的Curd数据处理,可重写对应的Before,After方法或重写整个数据操作方法来调整业务逻辑
    /// </para>
    /// <para>
    /// 更新实体时自动填充了更新时间的字段数据
    /// </para>
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <typeparam name="TKey"></typeparam>
    /// <typeparam name="TCreateDto"></typeparam>
    /// <typeparam name="TUpdateDto"></typeparam>
    /// <typeparam name="TListDto"></typeparam>
    /// <typeparam name="TDetailDto"></typeparam>
    /// <typeparam name="TFilterParams"></typeparam>
    /// <typeparam name="TSortParams"></typeparam>
    public abstract class CurdAuditAppService<TEntity, TKey, TCreateDto, TUpdateDto, TListDto, TDetailDto, TFilterParams, TSortParams> : CurdAppService<TEntity, TKey, TCreateDto, TUpdateDto, TListDto, TDetailDto, TFilterParams, TSortParams>
        where TEntity : PrivateEntity<TKey>, new()
        where TCreateDto : class, new()
        where TUpdateDto : class, new()
        where TListDto : class, new()
        where TDetailDto : class, new()
        where TFilterParams : Core.Base.BaseFilterParams<TEntity>, new()
        where TSortParams : Core.Base.BaseSortParams, new()
    {
        /// <summary>
        /// Cure应用服务基类(带审计属性)
        /// </summary>
        /// <param name="repository"></param>
        protected CurdAuditAppService(IRepository<TEntity> repository)
            : base(repository)
        {

        }

        protected override void AfterUpdate(TUpdateDto input, TEntity oldEntity, TEntity newEntity)
        {
            base.AfterUpdate(input, oldEntity, newEntity);

            newEntity.UpdatedTime = DateTimeOffset.UtcNow; // 更新时间
        }
    }


    /// <summary>
    /// Curd应用服务基类(带审计属性)
    /// <para>
    /// 实现了基本的Curd数据处理,可重写对应的Before,After方法或重写整个数据操作方法来调整业务逻辑
    /// </para>
    /// </summary>
    /// <typeparam name="TEntity">数据库实体</typeparam>
    /// <typeparam name="TKey">主键类型</typeparam>
    /// <typeparam name="TCreateDto">创建Dto</typeparam>
    /// <typeparam name="TUpdateDto">更新Dto</typeparam>
    /// <typeparam name="TListDto">列表Dto</typeparam>
    /// <typeparam name="TDetailDto">明细Dto</typeparam>
    /// <typeparam name="TFilterParams">过滤参数</typeparam>
    /// <typeparam name="TSortParams">排序参数</typeparam>
    public abstract class CurdAppService<TEntity, TKey, TCreateDto, TUpdateDto, TListDto, TDetailDto, TFilterParams, TSortParams> : ReadOnlyAppService<TEntity, TKey, TListDto, TDetailDto, TFilterParams, TSortParams>,
        ICurdAppService<TEntity, TKey, TCreateDto, TUpdateDto, TListDto, TDetailDto, TFilterParams, TSortParams>
        where TEntity : PrivateEntityBase<TKey>, new()
        where TCreateDto : class, new()
        where TUpdateDto : class, new()
        where TListDto : class, new()
        where TDetailDto : class, new()
        where TFilterParams : Core.Base.BaseFilterParams<TEntity>, new()
        where TSortParams : Core.Base.BaseSortParams, new()
    {


        /// <summary>
        /// Cure应用服务基类
        /// </summary>
        /// <param name="repository"></param>
        protected CurdAppService(IRepository<TEntity> repository)
            : base(repository)
        {

        }

        /// <summary>
        /// 插入一条数据
        /// </summary>
        /// <param name="dto"></param>
        [UnitOfWork]
        [SecurityDefine]
        public virtual void Create(TCreateDto dto)
        {
            var entity = dto.Adapt<TEntity>();
            BeforeCreate(dto, entity);
            _appRepository.InsertNow(entity);
            AfterCreate(dto, entity);
        }

        /// <summary>
        /// 插入数据前
        /// </summary>
        /// <param name="dto"></param>
        /// <param name="entity"></param>
        protected virtual void BeforeCreate(TCreateDto dto, TEntity entity)
        {

        }

        /// <summary>
        /// 插入数据化
        /// </summary>
        /// <param name="dto"></param>
        /// <param name="TEntity"></param>
        protected virtual void AfterCreate(TCreateDto dto, TEntity TEntity)
        {

        }

        /// <summary>
        /// 更新数据
        /// </summary>
        /// <param name="id"></param>
        /// <param name="dto"></param>
        [UnitOfWork]
        [SecurityDefine]
        public virtual void Update([ApiSeat(ApiSeats.ActionStart)] TKey id, [FromBody] TUpdateDto dto)
        {
            var entity = dto.Adapt<TEntity>();
            var history = _appRepository.FirstOrDefault(t => t.Id.Equals(id), false);
            if (history == null) throw Oops.Bah($"未能找到ID为 {id} 的数据");
            var update = BeforeUpdate(dto, history, entity);
            _appRepository.Update(update, true);
            AfterUpdate(dto, history, update);
        }

        /// <summary>
        /// 更新前
        /// </summary>
        /// <param name="input"></param>
        /// <param name="oldEntity"></param>
        /// <param name="newEntity"></param>
        /// <param name="ignoreProperties"></param>
        protected virtual TEntity BeforeUpdate(TUpdateDto input, TEntity oldEntity, TEntity newEntity, params string[] ignoreProperties)
        {
            // 忽略了常规只读字段属性
            var defaultIgnoreProps = new string[] { "Id", "CreatedTime", "IsDelete" };

            return oldEntity.AsMergeObject(newEntity, defaultIgnoreProps.Union(ignoreProperties).Distinct().ToArray());
        }

        /// <summary>
        /// 更新后
        /// </summary>
        /// <param name="input"></param>
        /// <param name="oldEntity"></param>
        /// <param name="newEntity"></param>
        protected virtual void AfterUpdate(TUpdateDto input, TEntity oldEntity, TEntity newEntity)
        {

        }

        /// <summary>
        /// 删除一个或多个
        /// </summary>
        /// <param name="ids"></param>
        [UnitOfWork]
        [SecurityDefine]
        public virtual void Delete([FromBody] IList<TKey> ids)
        {
            var deleteEntities = _appRepository.AsQueryable(false)
                .Where(t => ids.Contains(t.Id));

            BeforeDelete(ids, deleteEntities);
            _appRepository.Delete(deleteEntities);
            AfterDelete(ids, deleteEntities);
        }

        /// <summary>
        /// 删除前处理
        /// </summary>
        /// <param name="ids"></param>
        /// <param name="entities"></param>
        protected virtual void BeforeDelete(IList<TKey> ids, IQueryable<TEntity> entities)
        {

        }

        /// <summary>
        /// 删除后处理
        /// </summary>
        /// <param name="ids"></param>
        /// <param name="entities"></param>
        protected virtual void AfterDelete(IList<TKey> ids, IQueryable<TEntity> entities)
        {

        }
    }
}
